package com.gitee.cnzhangjie.excel.convert;

import com.gitee.cnzhangjie.excel.util.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FormulaError;

import java.text.DecimalFormat;
import java.util.Date;

final class CellType {
    /**
     * 根据单元格的类型返回相应类型的数值
     *
     * @param cell  单元格
     * @param clazz 类字段类型
     * @return 类字段值
     */
    static Object valueOf(Cell cell, Class<?> clazz) {
        // 实体属性类型优先，至高无上
        switch (cell.getCellType()) {
            case STRING:
                return valueOfString(cell, clazz);
            case NUMERIC:
                return valueOfNumeric(cell, clazz);
            case FORMULA:
                return valueOfFormula(cell, clazz);
            case BLANK:
                return valueOfBlank();
            case BOOLEAN:
                return valueOfBoolean(cell, clazz);
            case ERROR:
                return valueOfError(cell, clazz);
            default:
                return null;
        }
    }

    /**
     * 根据String转成clazz类型的对象
     *
     * @param cell  单元格
     * @param clazz 字段类型
     * @return clazz类型的对象
     */
    private static Object valueOfString(Cell cell, Class<?> clazz) {
        String s = cell.getStringCellValue();
        Object o = null;
        if (clazz.isAssignableFrom(Byte.class)) {
            o = Byte.parseByte(s);
        } else if (clazz.isAssignableFrom(Short.class)) {
            o = Short.parseShort(s);
        } else if (clazz.isAssignableFrom(Integer.class)) {
            o = Integer.parseInt(s);
        } else if (clazz.isAssignableFrom(Long.class)) {
            o = Long.parseLong(s);
        } else if (clazz.isAssignableFrom(Float.class)) {
            o = Float.parseFloat(s);
        } else if (clazz.isAssignableFrom(Double.class)) {
            o = Double.parseDouble(s);
        } else if (clazz.isAssignableFrom(Character.class)) {
            o = StringUtils.toChar(s);
        } else if (clazz.isAssignableFrom(String.class)) {
            o = s;
        }
        return o;
    }

    /**
     * 根据Numeric转成clazz类型的对象
     *
     * @param cell  单元格
     * @param clazz 字段类型
     * @return clazz类型的对象
     */
    private static Object valueOfNumeric(Cell cell, Class<?> clazz) {
        // 时间
        if (clazz.isAssignableFrom(Date.class)) {
            return cell.getDateCellValue();
        }
        // 数字
        double d = cell.getNumericCellValue();
        Object o = null;
        if (clazz.isAssignableFrom(Boolean.class)) {
            byte b = (byte) d;
            o = b != 0;
        } else if (clazz.isAssignableFrom(Byte.class)) {
            o = (byte) d;
        } else if (clazz.isAssignableFrom(Short.class)) {
            o = (short) d;
        } else if (clazz.isAssignableFrom(Integer.class)) {
            o = (int) d;
        } else if (clazz.isAssignableFrom(Long.class)) {
            o = (long) d;
        } else if (clazz.isAssignableFrom(Float.class)) {
            o = (float) d;
        } else if (clazz.isAssignableFrom(Double.class)) {
            o = d;
        } else if (clazz.isAssignableFrom(Character.class)) {
            o = StringUtils.toChar(String.valueOf(d));
        } else if (clazz.isAssignableFrom(String.class)) {
            // 删除分隔符
            o = new DecimalFormat().format(d).replaceAll(",", "");
        }
        return o;
    }

    /**
     * 根据Formula转成clazz类型的对象
     *
     * @param cell  单元格
     * @param clazz 字段类型
     * @return clazz类型的对象
     */
    private static Object valueOfFormula(Cell cell, Class<?> clazz) {
        if (clazz.isAssignableFrom(String.class)) {
            try {
                // 可能是字符串类型的公式，异常，则尝试数字
                return cell.getStringCellValue();
            } catch (IllegalStateException ignored) {
            }
        }
        return valueOfNumeric(cell, clazz);
    }

    /**
     * 返回null
     */
    private static Object valueOfBlank() {
        return null;
    }

    /**
     * 根据Boolean转成clazz类型的对象
     *
     * @param cell  单元格
     * @param clazz 字段类型
     * @return clazz类型的对象
     */
    private static Object valueOfBoolean(Cell cell, Class<?> clazz) {
        boolean b = cell.getBooleanCellValue();
        Object o = null;
        // 采用类似C语言，1为true，0为false
        if (clazz.isAssignableFrom(Boolean.class)) {
            o = b;
        } else if (clazz.isAssignableFrom(Byte.class)) {
            o = b ? (byte) 1 : (byte) 0;
        } else if (clazz.isAssignableFrom(Short.class)) {
            o = b ? (short) 1 : (short) 0;
        } else if (clazz.isAssignableFrom(Integer.class)) {
            o = b ? 1 : 0;
        } else if (clazz.isAssignableFrom(Long.class)) {
            o = b ? (long) 1 : (long) 0;
        } else if (clazz.isAssignableFrom(Float.class)) {
            o = b ? (float) 1 : (float) 0;
        } else if (clazz.isAssignableFrom(Double.class)) {
            o = b ? (double) 1 : (double) 0;
        } else if (clazz.isAssignableFrom(Character.class)) {
            o = b ? '1' : '0';
        } else if (clazz.isAssignableFrom(String.class)) {
            o = b ? "true" : "false";
        }
        return o;
    }

    /**
     * 根据Error转成clazz类型的对象
     *
     * @param cell  单元格
     * @param clazz 字段类型
     * @return clazz类型的对象，返回错误代码。
     * @see org.apache.poi.ss.usermodel.FormulaError
     */
    private static Object valueOfError(Cell cell, Class<?> clazz) {
        byte b = cell.getErrorCellValue();
        Object o = null;
        boolean isValidCode = FormulaError.isValidCode(b);
        // 采用类似C语言，1为true，0为false
        if (clazz.isAssignableFrom(FormulaError.class)) {
            if (isValidCode) {
                o = FormulaError.forInt(b);
            }
        } else if (clazz.isAssignableFrom(Boolean.class)) {
            o = isValidCode;
        } else if (clazz.isAssignableFrom(Byte.class)) {
            o = b;
        } else if (clazz.isAssignableFrom(Short.class)) {
            o = (short) b;
        } else if (clazz.isAssignableFrom(Integer.class)) {
            o = (int) b;
        } else if (clazz.isAssignableFrom(Long.class)) {
            o = (long) b;
        } else if (clazz.isAssignableFrom(Float.class)) {
            o = (float) b;
        } else if (clazz.isAssignableFrom(Double.class)) {
            o = (double) b;
        } else if (clazz.isAssignableFrom(Character.class)) {
            o = (char) (b);
        } else if (clazz.isAssignableFrom(String.class)) {
            o = String.valueOf((char) (b));
        }
        return o;
    }

    /**
     * 根据类字段类型为单元格赋值
     *
     * @param cell       单元格
     * @param fieldValue 该单元格的字段值
     */
    static void parse(
            final Cell cell,
            final Object fieldValue,
            final CellStyle dateCellStyle
    ) {
        if(fieldValue == null) {
            cell.setCellValue("");
            return;
        }
        Class<?> fieldValueClass = fieldValue.getClass();
        // 时间
        if (fieldValueClass.isAssignableFrom(Date.class)) {
            cell.setCellStyle(dateCellStyle);
            cell.setCellValue((Date) fieldValue);
        } else if (fieldValueClass.isAssignableFrom(FormulaError.class)) {
            // 错误
            cell.setCellErrorValue(((FormulaError) fieldValue).getCode());
        } else if (fieldValueClass.isAssignableFrom(Boolean.class)) {
            cell.setCellValue((boolean) fieldValue);
        } else if (fieldValueClass.isAssignableFrom(Byte.class)) {
            cell.setCellValue((byte) fieldValue);
        } else if (fieldValueClass.isAssignableFrom(Short.class)) {
            cell.setCellValue((short) fieldValue);
        } else if (fieldValueClass.isAssignableFrom(Integer.class)) {
            cell.setCellValue((int) fieldValue);
        } else if (fieldValueClass.isAssignableFrom(Long.class)) {
            cell.setCellValue((long) fieldValue);
        } else if (fieldValueClass.isAssignableFrom(Float.class)) {
            cell.setCellValue((float) fieldValue);
        } else if (fieldValueClass.isAssignableFrom(Double.class)) {
            cell.setCellValue((double) fieldValue);
        } else if (fieldValueClass.isAssignableFrom(Character.class)) {
            cell.setCellValue(StringUtils.valueOf((char) fieldValue));
        } else if (fieldValueClass.isAssignableFrom(String.class)) {
            cell.setCellValue((String) fieldValue);
        }
    }
}
